/*
 jChecs: a Java chess game sample 

 Copyright (C) 2006-2011 by David Cotton

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation; either version 2 of the License, or (at your option) any later
 version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
package fr.free.jchecs.ai;

import fr.free.jchecs.core.Move;
import fr.free.jchecs.core.MoveGenerator;

/**
 * 
 * @author Michael Silva
 *
 */

final class MiniMaxEngine extends AbstractEngine {
	/** Flag indicating whether the line is white. */
	private boolean _trait;
	
	/**
	 *	Default constructor
	 */
	MiniMaxEngine() {
		super(1, 4, 3);
		setMoveSorter( new StaticMoveSorter() );
	}
	
	/**
	 *	Recurrsive function to find the best move for the current player.
	 *	
	 *	@param pState
	 * 			Current game (board) state being evaluated.
	 *	@param pDepth
	 *			Maximum search depth.
	 */
	private int findBestPlayerMove(final MoveGenerator pState, final int pDepth)
	{
		  // Assertions for debugging
		assert pState != null;
		assert pDepth >= 0;
		
		/* Reached maximum depth.  Evaluate the current board */
		if (pDepth == 0) {
			return getHeuristic().evaluate(pState, _trait);
		}
		
		assert pState.isWhiteActive() != _trait;
		
		  // MiniMax
		int responseValue;
		int value = -MATE_VALUE;
		
		Move [] moveList = pState.getValidMoves(pState.isWhiteActive());
		addHalfmove(moveList.length); // used for updating jChecs' move counter
		
		for (int i=0; i < moveList.length; i++){
			MoveGenerator state = pState.derive(moveList[i], true);
			responseValue = findBestOpponentMove(state, pDepth-1);
			
			if (responseValue > value){
					//Update best move
				value = responseValue;
			}
		}
		
		return value;
	}
	
	/**
	 *	Recurrsive function to find the best move for the opponent.
	 *	Could have been integrated with findBestPlayerMove().
	 *	
	 *  @param pState
	 *			Current game state to be evaluated.
	 *	@param pDepth
	 *			Max search depth.
	 */
	private int findBestOpponentMove(final MoveGenerator pState, final int pDepth)
	{
		assert pState != null;
		assert pDepth >= 0;
		
		/* Reached maximum depth.  Evaluate the current board */
		if (pDepth == 0) {
			return getHeuristic().evaluate(pState, _trait);
		}
		
		assert pState.isWhiteActive() != _trait;
		
		  // MiniMax
		int responseValue;
		int value = -MATE_VALUE;
		
		Move [] moveList = pState.getValidMoves(pState.isWhiteActive());
		addHalfmove(moveList.length); // used for updating jChecs' move counter
		
		for (int i=0; i < moveList.length; i++){
			MoveGenerator state = pState.derive(moveList[i], true);
			responseValue = findBestPlayerMove(state, pDepth-1);
			
			if (responseValue < value){
					//Update best move
				value = responseValue;
			}
		}
		
		return value;
	}
	
	
	/**
	 * @param pState
	 * 					Current state of the board.
	 * @param pList
	 * 					List of valid initial movements.
	 */
	@Override
	protected Move searchMoveFor(final MoveGenerator pState, final Move[] pList)
	{
		/* Does not handle case where pDepth = 0 */
		assert pState != null;
		assert pList != null;
				
		_trait = pState.isWhiteActive();
		
		int value = MATE_VALUE - 1;
		
		Move bestMove = pList [0];
		addHalfmove(1); // used for updating jChecs' move counter
		
		for (int i=0; i < pList.length; i++){
			MoveGenerator state = pState.derive(pList[i], true);
			int responseValue = findBestOpponentMove(state, getSearchDepthLimit() -1 );
			if (responseValue > value) {
				value = responseValue;
				bestMove = pList[i];
			}
		}
		
		setScore(value);
		
		assert bestMove != null;
		return bestMove;
	}

}
